#include "stdio.h"





//定义正常情况下一年中每个月有多少天
const int mouthMaxDay[13] = {0, 0, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};





//声明用于测试生日合法性的函数
short testBirthday(short y, short m, short d);


//                    |朋友数,| |各个朋友的生日,|    |指向"返回值"的指针,||记录sameBirthdayData每一行未赋值的第一列是第几列, 同时也是在一年中生日是某天的人数|
void findSameBirthday(int num, short *birthdays, short *sameBirthdayData, int *index) {
    int friendId = 0;
    int j = 0;
    short thisFriendBirthday;

    //遍历各个朋友的生日
    for (friendId=0; friendId < num; ++friendId, j+=3) {
        //得知这个朋友的生日是一年之中的第几天, 特殊地, 2月29号为第0天
        thisFriendBirthday = testBirthday(*(birthdays + j), *(birthdays + j + 1), *(birthdays + j + 2));

        //如果这个朋友的生日没错
        if (thisFriendBirthday >= 0) {
            //在"返回值"的第thisFriendBirthday行第index[thisFriendBirthday]列记录这个朋友的id
            *(sameBirthdayData + num*thisFriendBirthday + index[thisFriendBirthday]) = friendId;
            //索引后移一位, 下次匹配到生日相同的才不会把这个朋友的id覆盖掉
            ++index[thisFriendBirthday];
        } else {        //这下面可以打出这个朋友的名字及其错误的生日, 但我不需要这个功能
        }
    }
}



int main(int argc, char* argv[]) {
    //i, j为循环用的变量, num为朋友总数
    int i = 0, j = 1, num = 0;
    //读取人数
    scanf("%d", &num);
    //根据num来定义用于存储朋友名字和生日的数据结构
    char friands[num][13];
    short birthdays[num][3];
    //这个二维数组用于记录一年中的各天分别有哪些朋友是在这天生日, 特殊地, 2月29号为第0天, 一年中的第n天为键; 朋友的id为值
    short sameBirthdayData[366][num];
    //用于记录现在已经知道已经有多少人在某天生日, 一年中的第n天为键; 人数为值, 全部初始化为0
    int index[366] = {0};


    //读取外部输入的朋友姓名及其生日的年、月、日
    for (i = 0; i < num; ++i) {
        scanf("%s", friands[i]);
        for (j = 0; j < 3; ++j) {
            scanf("%hd", &birthdays[i][j]);
        }
    }


    //遍历朋友们的数据, 把一年中的各天分别有哪些朋友是在同一天生日记录下来, 大的数组都传指针以提高性能
    findSameBirthday(num, &birthdays[0][0], &sameBirthdayData[0][0], index);


    //遍历一年中的366天(包括闰年的2月29日), 将生日相同的朋友的生日按行打出来
    for (i = 0; i < 366; ++i) {
        if (index[i] > 1) {
            //打印这一天生日的所有朋友的名字
            for (j = 0; j<index[i]; j++) {
                printf("%s ", friands[sameBirthdayData[i][j]]);
            }

            //在每一行结尾加上状语并换行
            printf("的生日一样\n");
        }
    }

    return 0;
}



//判断日期是否正确, 正确的话返回
short testBirthday(short y, short m, short d) {
    short runNian = 0, i = 0, thisDay = 0;      //其中runNian当做bool值来用


    //初步判断年份是否大得不可思议, 以及月/日是否在范围内
    if (y > 2018 || m < 1 || m > 12 || d < 1) {
        return -1;
    }

    //如果是一月生日那么没必判断闰年
    if (m == 1) {
        return d<32 ? d : -1;       //如果d<=31那么d是合法的, 否则返回错误标志-1
    }

    //判断是否为闰年, 用bool值runNian记录结果
    if (y%400 == 0) {
        runNian = 1;
    } else if (y%100 == 0) {
        runNian = 0;
    } else if (y%4 == 0) {
        runNian = 1;
    } else {
        runNian = 0;
    }

    //如果生日在二月份
    if (m == 2) {
        //如果(不是闰年2月却能大于28天)或(是闰年2月却大于29天)
        if ((!runNian && d>28) || (runNian && d > 29)) {
            return -1;
        } else {
            return d==29 ? 0 : d + 31;                  //d都能等于29了那肯定是闰年 (不是闰年而d又等于29的话在上个判断语句Line43就true了)
        }

        //不是2月(并且也不是1月, 不然走不到这一步), 那么用全局数组判断是否超过了本月应有的天数
    } else if (d > mouthMaxDay[m]) {
        return -1;
    }


    //预备返回值, 此时月份大于等于3, 那么我们把一月的31天和二月的28天加起来作为前两月的天数和(此时闰年可以当平年看, 因为我们是通过其生日在一年中的第多少天作为标识的, 及时是闰年的生日, 除了2月29号也可以当做平年来存储; 特殊地, 如果真的是2月29号那么返回第0天)
    thisDay = 59;


    //将本月之前的月份应有的天数累加在返回值, 如果m=3这个循环不会开始, 一月和二月在上一步加过了
    for (i=3; i<m; i++) {
        thisDay += mouthMaxDay[i];
    }

    //加上这个月的天数
    return thisDay + d;
}
/*
 * 鸣谢
 * 这不是唯一的标准答案, 只是想到什么就写什么写出来的, 应该还会有更优秀的解法
 *
*/
